package com.pig4cloud.pig.village.rules.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.pig4cloud.common.drools.DynamicRuleService;
import com.pig4cloud.pig.village.api.CommonConst;
import com.pig4cloud.pig.village.api.entity.*;
import com.pig4cloud.pig.village.collect.service.ICollectInfoService;
import com.pig4cloud.pig.village.family.service.IFamilyService;
import com.pig4cloud.pig.village.reward.service.IRewardService;
import com.pig4cloud.pig.village.rules.DataCollect;
import com.pig4cloud.pig.village.rules.FamilyData;
import com.pig4cloud.pig.village.rules.TeamData;
import com.pig4cloud.pig.village.rules.VillagerData;
import com.pig4cloud.pig.village.rules.generator.RulesGenerator;
import com.pig4cloud.pig.village.rules.service.IRuleService;
import com.pig4cloud.pig.village.schedule.service.IScheduleService;
import com.pig4cloud.pig.village.team.service.ITeamService;
import com.pig4cloud.pig.village.villager.service.IVillagerService;
import com.pig4cloud.pig.village.welfare.service.IWelfareRuleService;
import lombok.extern.slf4j.Slf4j;
import org.kie.api.runtime.KieSession;
import org.springframework.stereotype.Service;

import static com.pig4cloud.pig.village.api.CommonConst.JOB_BIRTHMONTH;
import static com.pig4cloud.pig.village.api.CommonConst.TIME_DIMENSION_ONCE;

/**
 * 按照规则处理数据，返回处理结果
 * @author limbray.li
 * @date 2021/7/22
 */
@Service
@Slf4j
public class RuleServiceImpl implements IRuleService {
	@Resource
	private IWelfareRuleService welfareRuleService;
	@Resource
	private ITeamService teamService;
	@Resource
	private IFamilyService familyService;
	@Resource
	private IVillagerService villagerService;
	@Resource
	private IRewardService rewardService;
	@Resource
	private IScheduleService scheduleService;
	@Resource
	private ICollectInfoService collectInfoService;

	@Override
	public Boolean dealRuleByEvent(Long eventId) {
		//TODO 查询event
		return null;
	}

	@Override
	public Boolean dealRuleByEvent(RewardEvent event) {
		//通过event找到关系人
		DataCollect collect = getDataCollectByEvent(event);
		return dealRuleByEvent(collect, event);
	}

	@Override
	public Boolean dealRuleByEvent(RewardEvent event, RewardInfo info) {
		//通过event找到关系人
		DataCollect collect = getDataCollectByEvent(event, info);
		return dealRuleByEvent(collect, event);
	}

	@Override
	public Boolean dealRuleByEvent(DataCollect collect, RewardEvent event) {
		//事件找到规则
		//data结合规则计算金额
		// Villager
		KieSession kieSession = DynamicRuleService.getInstance().getRuleSession(collect.getRuleCode(), "v" + event.getYear());
		if (kieSession != null && CollectionUtils.isNotEmpty(collect.getVillagers())) {
			for (VillagerData data : collect.getVillagers()) {
				kieSession.insert(data);
				kieSession.fireAllRules();
			}
		}
		// Family
		kieSession = DynamicRuleService.getInstance().getRuleSession(collect.getRuleCodeFamily(), "v" + event.getYear());
		if (kieSession != null && CollectionUtils.isNotEmpty(collect.getFamilys())) {
			for (FamilyData data : collect.getFamilys()) {
				kieSession.insert(data);
				kieSession.fireAllRules();
			}
		}
		// Team
		kieSession = DynamicRuleService.getInstance().getRuleSession(collect.getRuleCodeTeam(), "v" + event.getYear());
		if (kieSession != null && CollectionUtils.isNotEmpty(collect.getTeams())) {
			for (TeamData data : collect.getTeams()) {
				kieSession.insert(data);
				kieSession.fireAllRules();
			}
		}
		//金额保存到数据库
		saveAmount(collect, event);
		//更新红黑榜
		updateRewardInfo(collect, event);
		return true;
	}

	private boolean updateRewardInfo(DataCollect collect, RewardEvent event) {
		if (StringUtil.isNotBlank(event.getScheduleCode())) {
			return true;
		}
//		String familyAmount = collect.getFamilys().stream().filter(e -> e.isMatch() != false).map(FamilyData::getAmount).findAny().get();
		String familyAmount = collect.getFamilys().stream().filter(e -> e.isMatch() != false).map(FamilyData::getAmount).findAny().orElse(null);
		BigDecimal amoutnFamily = new BigDecimal(familyAmount == null ? "0" : familyAmount);
//		String teamAmount = collect.getTeams().stream().filter(e -> e.isMatch() != false).map(TeamData::getAmount).findAny().get();
		String teamAmount = collect.getTeams().stream().filter(e -> e.isMatch() != false).map(TeamData::getAmount).findAny().orElse(null);
		BigDecimal amountTeam = new BigDecimal(teamAmount == null ? "0" : teamAmount);
		//更新红黑榜的3个金额
		rewardService.updateRewardAmount(event.getId(), amoutnFamily, amountTeam);
		return true;
	}

	/**
	 * 保存最终的金额结果
	 * @param collect
	 * @param event
	 * @return
	 */
	private boolean saveAmount(DataCollect collect, RewardEvent event) {
		List<CollectInfo> infos = new ArrayList<>();
		//定时任务执行默认生效
		Integer status = StringUtil.isNotBlank(event.getScheduleCode()) ? 1 : 0;
		Integer year = event.getEventTime().getYear();
		Integer month = event.getEventTime().getMonthValue();
		//先保存到金额统计表：collect_info
		//人
		if (collect.getVillagers() != null) {
			List<VillagerData> villagerData = collect.getVillagers().stream().filter(e -> e.isMatch()).collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(villagerData)) {
				for (VillagerData data : villagerData) {
					CollectInfo info = new CollectInfo(status, new BigDecimal(data.getAmount()), event.getId(), collect.getWelfareId(), year, month);
					info.setType(0);
					info.setVillagerId(data.getVillagerId());
					infos.add(info);
				}
			}
		}
		//户
		if (collect.getFamilys() != null) {
			List<FamilyData> familyData = collect.getFamilys().stream().filter(e -> e.isMatch()).collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(familyData)) {
				for (FamilyData data : familyData) {
					CollectInfo info = new CollectInfo(status, new BigDecimal(data.getAmount()), event.getId(), collect.getWelfareId(), year, month);
					info.setType(1);
					info.setFamilyId(data.getFamilyId());
					infos.add(info);
				}
			}
		}
		//村
		if (collect.getTeams() != null) {
			List<TeamData> teamData = collect.getTeams().stream().filter(e -> e.isMatch()).collect(Collectors.toList());
			if (CollectionUtils.isNotEmpty(teamData)) {
				for (TeamData data : teamData) {
					CollectInfo info = new CollectInfo(status, new BigDecimal(data.getAmount()), event.getId(), collect.getWelfareId(), year, month);
					info.setType(2);
					info.setTeamId(data.getTeamId());
					infos.add(info);
				}
			}
		}

		if (CollectionUtils.isNotEmpty(infos)) {
			collectInfoService.removeByEvent(event.getId());
			collectInfoService.saveBatch(infos);
		}
		return true;
	}

	/**
	 * 获得相关的人、户、队
	 * @param event
	 * @return
	 */
	private DataCollect getDataCollectByEvent(RewardEvent event) {
		DataCollect result = new DataCollect();
		if (event != null) {
//			if (StringUtil.isNotBlank(event.getScheduleCode()) && event.getTimeDimension() != CommonConst.TIME_DIMENSION_ONCE) {
			if (StringUtil.isNotBlank(event.getScheduleCode())) {
				//定时任务模式
				result = scheduleCollect(event);
			} else {
				//红黑榜事件模式
				result = rewardCollect(event, null);
			}
		}
		return result;
	}

	/**
	 * 获得相关的人、户、队（红黑榜）
	 *
	 * @param event
	 * @return
	 */
	private DataCollect getDataCollectByEvent(RewardEvent event, RewardInfo info) {
		DataCollect result = new DataCollect();
		if (event != null) {
//			if (StringUtil.isNotBlank(event.getScheduleCode()) && event.getTimeDimension() != CommonConst.TIME_DIMENSION_ONCE) {
			if (StringUtil.isNotBlank(event.getScheduleCode())) {
				//定时任务模式
				result = scheduleCollect(event);
			} else {
				//红黑榜事件模式
				result = rewardCollect(event, info);
			}
		}
		return result;
	}

	/**
	 * 定时任务数据统计
	 * @param event
	 * @return
	 */
	public DataCollect scheduleCollect(RewardEvent event) {
		DataCollect dataCollect = null;
		//查询能够通过定时任务的人
		List<Villager> villagers = villagerService.list();
		villagers = villagers.stream().filter(e -> e.getDeadDate() == null).collect(Collectors.toList());
		if (StringUtil.equals(CommonConst.JOB_BIRTHMONTH, event.getScheduleCode())) {
			//生日任务：筛选这个月过生日的村民
			villagers = villagers.stream().filter(e -> e.getBirthDate().getMonthValue() == event.getMonth()).collect(Collectors.toList());
			List<VillagerData> villagerDatas = villagerConvert(villagers);
			dataCollect = new DataCollect(villagerDatas, null, null);
		} else {
			//非生日任务，所有的村民、户、队
			List<VillagerData> villagerDatas = villagerConvert(villagers);
			//户
			List<Family> families = familyService.list();
			List<FamilyData> familyDatas = familyConvert(families, null);
			//队
			List<Team> teams = teamService.list();
			List<TeamData> teamDatas = teamConvert(teams, null);
			dataCollect = new DataCollect(villagerDatas, familyDatas, teamDatas);
		}
		dataCollect.setTimeDimension(event.getTimeDimension());
		dataCollect.setYear(event.getYear());
		dataCollect.setRaise(1);
		dataCollect.setWelfareId(event.getScheduleWelfareId());
		return dataCollect;
	}

	/**
	 * 红黑榜事件，数据统计
	 * @param event
	 * @return
	 */
	private DataCollect rewardCollect(RewardEvent event, RewardInfo info) {
		//通过红黑榜来查询相关的人，户，队
		List<RewardInfo> infos = rewardService.listByEvent(event);
		List<Long> villagerIds = infos.stream().map(RewardInfo::getVillagerId).collect(Collectors.toList());
		List<Villager> villagers = villagerService.listByIds(villagerIds);
		List<Long> familyIds = infos.stream().map(RewardInfo::getFamilyId).collect(Collectors.toList());
		List<Family> families = familyService.listByIds(familyIds);
		List<Long> teamIds = infos.stream().map(RewardInfo::getTeamId).collect(Collectors.toList());
		List<Team> teams = teamService.listByIds(teamIds);
		//数据转化(只取后面用到的字段)
		List<VillagerData> villagerDatas = villagerConvert(villagers);
		List<FamilyData> familyDatas = familyConvert(families, info);
		List<TeamData> teamData = teamConvert(teams, info);
		// 部分信息会设定到户上
		// 下面的写法.get(0)目前只兼容于rewardEvent: rewardInfo为1:1的情况
		familyDatas.forEach(e -> {
			e.setLivingType(villagerDatas.get(0).getLivingType());
			e.setHardGroup(villagerDatas.get(0).getHardGroup());
		});
		//构造对象
		DataCollect dataCollect = new DataCollect(villagerDatas, familyDatas, teamData);
		dataCollect.setWelfareId(infos.get(0).getWelfareId());
		//异或操作，使红黑榜变成发放或扣除
		dataCollect.setRaise(infos.get(0).getPunishment() ^ 1);
		dataCollect.setTimeDimension(event.getTimeDimension());
		dataCollect.setYear(event.getYear());
		return dataCollect;
	}

	/**
	 * 村民转化
	 * @param villagers
	 * @return
	 */
	public List<VillagerData> villagerConvert(List<Villager> villagers) {
		List<VillagerData> villagerDatas = villagers.stream().map(e -> {
			VillagerData data = new VillagerData();
			Long age = e.getBirthDate().toLocalDate().until(LocalDate.now(), ChronoUnit.YEARS);
			data.setAge(age.intValue());
			data.setVillagerId(e.getId());
			data.setBirthMonth(e.getBirthDate().getMonthValue());
			data.setBirthDay(e.getBirthDate().getDayOfMonth());

			data.setLivingType(e.getLivingType()== null ? null : e.getLivingType().getCode());
			data.setOutsider(e.getOutsider()== null ? null : e.getOutsider().getCode());
			data.setPartyMember(e.getPartyMember()== null ? null : e.getPartyMember().getCode());
			data.setSpecialFamily(e.getSpecialFamily()== null ? null : e.getSpecialFamily().getCode());
			data.setHardGroup(e.getHardGroup()== null ? null : e.getHardGroup().getCode());
			data.setArmy(e.getArmy()== null ? null : e.getArmy().getCode());
			data.setSchool(e.getSchool()== null ? null : e.getSchool().getCode());
			data.setRetiredCaptain(e.getRetiredCaptain()== null ? null : e.getRetiredCaptain().getCode());
			data.setRetiredPrincipal(e.getRetiredPrincipal()== null ? null : e.getRetiredPrincipal().getCode());
//			TODO other 待定
//			BeanUtil.copyProperties(e, data);

			return data;
		}).collect(Collectors.toList());
		return villagerDatas;
	}

	/**
	 * 户转化
	 * @param families
	 * @return
	 */
	public List<FamilyData> familyConvert(List<Family> families, RewardInfo info) {
		List<FamilyData> familyDatas = families.stream().map(e -> {
			FamilyData data = new FamilyData();
			data.setFamilyId(e.getId());
			// 红黑榜福利取值
			if (info != null) {
				data.setWelfareId(info.getWelfareId());
				data.setViolationType(info.getViolationSubCode());
			}
			BeanUtil.copyProperties(e, data);
			return data;
		}).collect(Collectors.toList());
		return familyDatas;
	}

	/**
	 * 队转化
	 * @param teams
	 * @return
	 */
	public List<TeamData> teamConvert(List<Team> teams, RewardInfo info) {
		List<TeamData> teamDatas = teams.stream().map(e -> {
			TeamData data = new TeamData();
			data.setTeamId(e.getId());
			// 红黑榜福利取值
			if (info != null) {
				data.setWelfareId(info.getWelfareId());
				data.setViolationType(info.getViolationSubCode());
			}
			BeanUtil.copyProperties(e, data);
			return data;
		}).collect(Collectors.toList());
		return teamDatas;
	}

	private static String getTitle() {
		String s = "" +
				"package com.pig4cloud.pig.village \n" +
				"import com.pig4cloud.pig.village.rules.VillagerData \n" +
				"import com.pig4cloud.pig.village.rules.FamilyData \n" +
				"import com.pig4cloud.pig.village.rules.TeamData \n\n";
		return s;
	}

	@Override
	public Boolean saveRules(List<WelfareRule> list) {
		if (CollectionUtils.isEmpty(list)) {
			return false;
		}
		WelfareRule rule1 = list.get(0);
		//(welfareId+raise+timeDimension+groupDimension+year)
		String ruleCode = getRuleCode(rule1);
		log.info("ruleCode: {}", ruleCode);
		String version = "v" + rule1.getYear();
		String content = getTitle();
		for (WelfareRule rule : list) {
			String generatedRule = generateRule(rule, String.valueOf(rule.getId()));
			content += generatedRule;
			content += "\n";
		}
		content += ";";
		DynamicRuleService.getInstance().buildRuleContent(ruleCode, version, content);
		return true;
	}

	private String getRuleCode(WelfareRule rule) {
		return rule.getWelfareId() + "-" + rule.getRaise() + "-" + rule.getTimeDimension() + "-" + rule.getGroupDimension();
	}

	@Override
	public Boolean initRulesEngine() {
		//获取所有规则
		List<WelfareRule> rules = welfareRuleService.getAllRules();
//		//剔除无效规则(剔除数据库中rules字段为空的规则)
//		rules = rules.stream().filter(e -> StringUtil.isNotBlank(e.getRules())).collect(Collectors.toList());
		//规则分组,按照(welfareId+raise+timeDimension+groupDimension+year+租户)分组
		Map<String, List<WelfareRule>> map = rules.stream().collect(Collectors.groupingBy(e -> getRuleCode(e) + e.getYear() + e.getTenantId()));
		//依次构建
		map.values().forEach(e -> {
			try {
				saveRules(e);
				log.info("一条规则构建成功！");
			} catch (Exception exception) {
				log.error("一条规则构建失败:{}！", JSON.toJSONString(e));
				//继续构建！
			}
		});
		return true;
	}

	@Override
	public String generateRule(WelfareRule welfareRule, String ruleName) {
		return new RulesGenerator().generateRule(welfareRule, ruleName);
	}

}
